// PicoStreamOut.v - a stream coming from the firmware to the Pico bus
// Copyright 2006, Pico Computing, Inc.

//todo: eos
//      some real reset logic, taking different clock domains into account

`include "PicoDefines.v"

module PicoStreamOut #(
   parameter StreamNum  = 10,
   parameter Width      = 32,    //fixed
// parameter Depth      = 4096,  //fixed
   parameter StatusAddr = (`PICO_STREAM_STATUS_BASE + `PICO_STREAM_STATUS_SIZE*(StreamNum-1)),
   parameter DataAddr   = (`PICO_STREAM_BASE + `PICO_STREAM_SIZE*(StreamNum-1))
) (
   input Rst,
   // Pico/Channel bus signals
   input BusClk, input [31:0] BusAddr, input [31:0] BusDataIn, output [31:0] BusDataOut, input BusRead, input BusWrite,
   // Stream signals
   input StreamClk, input [Width-1:0] StreamData, output StreamRdy, input StreamEn, input StreamEOS
);

wire FifoAlmostFull, FifoAlmostEmpty, FifoEmpty, FifoFull;
wire [11:0] FifoReadCount;
wire [11:0] FifoWriteCount;
wire [31:0] FifoDataOut;

wire ReadStatusValid      = BusRead & ({BusAddr[31:2],   2'b0} == StatusAddr);
//making the fifo pointers accessible is temporary. don't depend on it.
wire ReadCountsValid      = BusRead & ({BusAddr[31:2],   2'b0} == (StatusAddr + 8));
wire ReadDataValid        = BusRead & ({BusAddr[31:20], 20'h0} == DataAddr); //note - ignoring bottom 20 bits

wire [31:0] ExtraStat     = {4'hb, FifoWriteCount[11:0], FifoEmpty, FifoAlmostEmpty, FifoFull, FifoAlmostFull, FifoReadCount[11:0]};
wire [19:0] FifoFreeCount = {8'h0, ((FifoWriteCount[11:0] == FifoReadCount[11:0]) & ~FifoEmpty) ? 12'h1 : FifoWriteCount[11:0] - FifoReadCount[11:0]};
wire [31:0] Status        = {`BM_READ_STATUS_SIGNATURE, 6'h0, FifoFreeCount[19:0]};
assign BusDataOut[31:0]   = ReadDataValid   ? FifoDataOut[31:0] : 
                            ReadStatusValid ? Status[31:0]      : 
                            ReadCountsValid ? ExtraStat[31:0]   : 32'h0;

//Note that due to the latency on FifoEmpty, we don't see the 'empty' signal till it's too late. We're trusting the software...
assign StreamRdy = ~FifoAlmostFull;
wire   FifoRead  = ~FifoEmpty & ReadDataValid;
wire   FifoWrite = StreamRdy & StreamEn;

//Following instantiates a fifo that is reps*4 bits wide and 4096 deep (property of fifo).
FIFO16_REP #(
    .REPS(1),
    .ALMOST_FULL_OFFSET(12'h10),    // Sets almost full threshold
    .ALMOST_EMPTY_OFFSET(12'h10),   // Sets the almost empty threshold
    .DATA_WIDTH(36),                // Sets data width to 4, 9, 18, or 36
    .FIRST_WORD_FALL_THROUGH("TRUE")// Sets the FIFO FWFT to "TRUE" or "FALSE"
) F16I (
    .ALMOSTEMPTY(FifoAlmostEmpty),  // 1-bit almost empty output flag
    .ALMOSTFULL(FifoAlmostFull),    // 1-bit almost full output flag
    .DO(FifoDataOut[31:0]),
    //.DOP(),
    .EMPTY(FifoEmpty),
    .FULL(FifoFull),
    .RDCOUNT(FifoReadCount),
    //.RDERR(),
    .WRCOUNT(FifoWriteCount),
    //.WRERR(),
    .DI(StreamData[31:0]),
    //.DIP(4'h0),
    .RDCLK(BusClk),
    .RDEN(FifoRead),
    .RST(Rst),                      // 1-bit reset input
    .WRCLK(StreamClk),              // 1-bit write clock input
    .WREN(FifoWrite)                // 1-bit write enable input
);

endmodule
